package Learn;

import java.io.File;
import java.util.List;

import mymath.MyMathOps;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public  class clusterparser {


	public static int CLUSTERORDINAL = 0;
	public static int CLUSTERNOMINAL = 1;

	/* 
	 *  Reads the clusterassignments contained in xml format in clusterfile.
	 *  If clusterfile contains k clusterings for n instances, then method
	 *  returns an (k+1) x (n+2) array. The first entry in each row is an indicator
	 *  for the type of the clustering: ordinal or categorical.
	 *  The second entry contains the number of clusters in this clusterin. 
	 *  The last row contains an index for the clustercombination of the first 
	 *  k rows.
	 */
	public static int[][] readClusters(String clusterfile){
		int[][] result = null;


		try{
			SAXReader reader = new SAXReader();
			File xmlfile = new File(clusterfile);
			Document doc = reader.read(xmlfile);
			Element root = doc.getRootElement();
			Element instel = root.element("Instances");
			Element metael = root.element("MetaData");
			List<Element> clusinfo = metael.elements("Layer");
			List<Element> instlist = instel.elements("Inst");
			
			int numinstances = instlist.size();

			Element firstinst = instlist.get(0);
			//List<Element> cluslist = firstinst.elements("Clus");
			int numclusterings = clusinfo.size();
			int[] clusdims = new int[numclusterings]; /* contains for each clustering the number of clusters in that
			clustering */
			result = new int[numclusterings+1][numinstances +2];

			/* Determine the types of clusterings 
			 * 
			 * It is assumed that categorical clusterings have clusterlabels of the form cX (X an integer)
			 * and ordinal clusterings have integer clusterlabels 
			 * */

			
			for (int  i = 0; i< clusinfo.size();i++){
				Element nextclus = clusinfo.get(i);
				String clustype = nextclus.attributeValue("type").trim();
				if (clustype.equals("nominal") || clustype.equals("n"))
					result[i][0] = CLUSTERNOMINAL;
				else
					result[i][0] = CLUSTERORDINAL;
				result[i][1] = Integer.parseInt(nextclus.attributeValue("size").trim());
			}


			/* 
			 *  Now fill in the actual cluster indices
			 */
			int thisindex;
			List<Element> cluslist;
			for (int  j = 0; j< instlist.size();j++){
				Element nextinst = instlist.get(j);
				cluslist = nextinst.elements("Clus");
				for (int  i = 0; i< cluslist.size();i++){
					int thisclustype = result[i][0];
					Element nextclus = cluslist.get(i);
					String clusval = nextclus.attributeValue("val").trim();
					if (thisclustype == CLUSTERNOMINAL)
						thisindex = Integer.parseInt(clusval.substring(1));
					else 
						thisindex = Integer.parseInt(clusval);
					result[i][j+2] = thisindex;
					clusdims[i]=Math.max(clusdims[i],thisindex+1);
				}		
			}
			/* 
			 *  Fill in the row with the combined index
			 */
			int[] instclusterings = new int[numclusterings];
			for (int  j = 0; j< instlist.size();j++){
				for (int i=0;i<numclusterings;i++)
					instclusterings[i] = result[i][j+2];
				result[numclusterings][j+2]= MyMathOps.arraytoindex(instclusterings,clusdims);
			}
		}

		catch (Exception e) {
			System.err.println(e);
		}
		return result;
	}

}
